Skip to content

feat: Add linkClaimAttemptToExternalUser to Agents module#1652

Merged
m0tzy merged 3 commits into
mainfrom
devin/1783009238-add-create-claim-attempt
Jul 21, 2026
Merged

feat: Add linkClaimAttemptToExternalUser to Agents module#1652
m0tzy merged 3 commits into
mainfrom
devin/1783009238-add-create-claim-attempt

Conversation

@m0tzy

@m0tzy m0tzy commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description

Adds workos.agents.linkClaimAttemptToExternalUser(options) wrapping PATCH /agents/claims/attempts.

The serializer hardcodes type: 'link_external_user' so callers don't need to pass it:

const result = await workos.agents.linkClaimAttemptToExternalUser({
  claimAttemptToken: 'cla_tkn_...',
  user: { email: 'alice@example.com', externalId: 'ext_alice' },
  organizationId: 'org_...', // optional
});
// result: { id, status, userCode, organizations }

Types: LinkClaimAttemptToExternalUserOptions, ClaimAttemptResponse, ClaimAttemptOrganization

The endpoint uses PATCH because it modifies an existing claim attempt (the agent already created it) rather than creating one. Generated SDKs surface a generic updateAttempts({ type: 'link_external_user', ... }); this hand-written SDK keeps the ergonomic linkClaimAttemptToExternalUser wrapper.

Documentation

[x] Yes

API reference docs updated in the companion monorepo PR (workos/workos#64535).

Closes AUTH-6647

Link to Devin session: https://app.devin.ai/sessions/4c6130f5dc744691a1c9fe409b253aac
Requested by: @m0tzy

Add POST /agents/claims/attempts endpoint support to the Node SDK.
This allows admin API consumers to attach a user to a claim attempt
and retrieve the code needed for the agent to complete the claim.

Closes AUTH-6647

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@m0tzy
m0tzy requested review from a team as code owners July 2, 2026 16:21
@m0tzy
m0tzy requested a review from dandorman July 2, 2026 16:21
@m0tzy m0tzy self-assigned this Jul 2, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor
Original prompt from madison.packer

Can we open a PR for this? https://linear.app/workos/issue/AUTH-6646/add-an-api-endpoint-to-the-agent-auth-admin-controller-for-retrieving

@linear-code

linear-code Bot commented Jul 2, 2026

Copy link
Copy Markdown

AUTH-6647

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot changed the title Add createClaimAttempt to Agents module feat: Add createClaimAttempt to Agents module Jul 2, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds workos.agents.linkClaimAttemptToExternalUser(options), a new method on the Agents class that calls PATCH /agents/claims/attempts to link an external user to a pending agent claim attempt and return the resulting ClaimAttemptResponse.

  • New interface file (claim-attempt.interface.ts) defines camelCase options and response types alongside their snake_case serialized counterparts, following the existing SDK pattern.
  • New serializer (claim-attempt.serializer.ts) hardcodes type: 'link_external_user', snake_cases all fields, and conditionally includes organization_id only when provided.
  • Tests cover the happy path, optional organizationId inclusion, and omission; the fixture file retains the pre-rename name create-claim-attempt.json.

Confidence Score: 4/5

The change is isolated to new code with no existing callers affected, but the HTTP verb used (PATCH) contradicts the PR description (POST), which needs confirmation against the actual API before shipping.

The implementation and tests consistently use PATCH, while the PR description documents the endpoint as POST. If the WorkOS backend only accepts POST at /agents/claims/attempts, every SDK call to this method will fail with a 405 response. The rest of the change — serialization, deserialization, types, and test coverage — is well-structured and follows the codebase patterns.

src/agents/agents.ts — the HTTP verb (PATCH vs POST) should be verified against the API spec before merging.

Important Files Changed

Filename Overview
src/agents/agents.ts Adds linkClaimAttemptToExternalUser using PATCH, which contradicts the PR description stating POST; the HTTP verb needs verification against the API spec.
src/agents/interfaces/claim-attempt.interface.ts New interface file with clean type definitions; minor inconsistency where SerializedClaimAttemptResponse.organizations uses the deserialized ClaimAttemptOrganization type instead of a dedicated serialized type.
src/agents/serializers/claim-attempt.serializer.ts Serializer correctly snake_cases all fields, hardcodes type: 'link_external_user', and conditionally omits organization_id; deserialization is straightforward.
src/agents/agents.spec.ts Good test coverage for the happy path, optional organizationId inclusion, and omission; tests consistently expect PATCH, which aligns with the implementation but contradicts the PR description.
src/agents/fixtures/create-claim-attempt.json New fixture with correct snake_case API response shape; file name (create-claim-attempt) is a minor leftover from the earlier method name before the rename.
src/agents/interfaces/index.ts Re-exports the new claim-attempt interface correctly.
src/agents/serializers/index.ts Re-exports the new claim-attempt serializer correctly.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant Agents as workos.agents
    participant Serializer as claim-attempt.serializer
    participant API as WorkOS API

    Caller->>Agents: linkClaimAttemptToExternalUser(options)
    Agents->>Serializer: serializeLinkClaimAttemptToExternalUserOptions(options)
    Note over Serializer: Hardcodes type: 'link_external_user'<br/>snake_cases claimAttemptToken to claim_attempt_token<br/>externalId to external_id<br/>Conditionally adds organization_id
    Serializer-->>Agents: SerializedLinkClaimAttemptToExternalUserOptions
    Agents->>API: PATCH /agents/claims/attempts
    API-->>Agents: SerializedClaimAttemptResponse (snake_case)
    Agents->>Serializer: deserializeClaimAttemptResponse(data)
    Note over Serializer: user_code to userCode
    Serializer-->>Agents: ClaimAttemptResponse (camelCase)
    Agents-->>Caller: ClaimAttemptResponse
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant Agents as workos.agents
    participant Serializer as claim-attempt.serializer
    participant API as WorkOS API

    Caller->>Agents: linkClaimAttemptToExternalUser(options)
    Agents->>Serializer: serializeLinkClaimAttemptToExternalUserOptions(options)
    Note over Serializer: Hardcodes type: 'link_external_user'<br/>snake_cases claimAttemptToken to claim_attempt_token<br/>externalId to external_id<br/>Conditionally adds organization_id
    Serializer-->>Agents: SerializedLinkClaimAttemptToExternalUserOptions
    Agents->>API: PATCH /agents/claims/attempts
    API-->>Agents: SerializedClaimAttemptResponse (snake_case)
    Agents->>Serializer: deserializeClaimAttemptResponse(data)
    Note over Serializer: user_code to userCode
    Serializer-->>Agents: ClaimAttemptResponse (camelCase)
    Agents-->>Caller: ClaimAttemptResponse
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/agents/agents.ts:67-70
**HTTP method contradicts the PR description**

The PR description explicitly states this wraps `POST /agents/claims/attempts`, but the implementation calls `this.workos.patch(...)`. If the WorkOS API endpoint only accepts `POST`, every call to `linkClaimAttemptToExternalUser` will fail with a `405 Method Not Allowed` response. The tests assert `'PATCH'` which keeps them consistent with the implementation, but they won't catch this kind of server-side rejection. Please confirm the intended HTTP verb against the API spec and align the implementation, tests, and PR description accordingly.

Reviews (3): Last reviewed commit: "Send claim attempt link request with PAT..." | Re-trigger Greptile

…d type discriminator

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat: Add createClaimAttempt to Agents module Add linkClaimAttemptToExternalUser to Agents module Jul 2, 2026
@devin-ai-integration devin-ai-integration Bot changed the title Add linkClaimAttemptToExternalUser to Agents module feat: Add linkClaimAttemptToExternalUser to Agents module Jul 2, 2026
Comment thread src/agents/agents.ts
@m0tzy m0tzy removed their assignment Jul 7, 2026
@m0tzy
m0tzy requested a review from a team July 7, 2026 21:47
Comment thread src/agents/agents.ts
* @throws {ConflictException} 409 - Organization selection required, external ID conflict, or already claimed.
* @throws {GoneException} 410 - Claim or user code expired.
*/
async linkClaimAttemptToExternalUser(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion here on the name, but just flagging that this is different from the other SDKs' generated method (createAttempt) so I'm wondering if we should rename this to something more similar or the same.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name was a deliberate choice by @m0tzy earlier in the design of this endpoint. The autogenerated SDKs surface a generic createAttempt(type=...) because they're driven directly off the OpenAPI operation, but for the hand-written Node method Madison wanted the name to describe what the operation actually does — link an external user to a claim attempt — rather than expose the lower-level type discriminator. The corresponding docs/API summary was also updated to "Link a claim attempt to an external user" to match.

Happy to rename to align with the generated SDKs (createAttempt) if the team would rather keep them consistent — deferring to @m0tzy on the final call since it was a product decision.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update on this: we resolved the divergence by switching the endpoint from POST to PATCH /agents/claims/attempts (it modifies an existing claim attempt rather than creating one — the agent already created it). The generated SDKs now surface a generic updateAttempts({ type: 'link_external_user', ... }), where the type arg disambiguates the operation. This hand-written Node SDK keeps the ergonomic linkClaimAttemptToExternalUser(...) wrapper over the same PATCH call (it hardcodes type internally). So the remaining name difference is intentional — hand-written SDKs are allowed to be friendlier than the generated ones. Server + docs are updated in workos/workos#64535.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Comment thread src/agents/agents.ts
Comment on lines +67 to +70
const { data } = await this.workos.patch<SerializedClaimAttemptResponse>(
'/agents/claims/attempts',
serializeLinkClaimAttemptToExternalUserOptions(options),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 HTTP method contradicts the PR description

The PR description explicitly states this wraps POST /agents/claims/attempts, but the implementation calls this.workos.patch(...). If the WorkOS API endpoint only accepts POST, every call to linkClaimAttemptToExternalUser will fail with a 405 Method Not Allowed response. The tests assert 'PATCH' which keeps them consistent with the implementation, but they won't catch this kind of server-side rejection. Please confirm the intended HTTP verb against the API spec and align the implementation, tests, and PR description accordingly.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/agents.ts
Line: 67-70

Comment:
**HTTP method contradicts the PR description**

The PR description explicitly states this wraps `POST /agents/claims/attempts`, but the implementation calls `this.workos.patch(...)`. If the WorkOS API endpoint only accepts `POST`, every call to `linkClaimAttemptToExternalUser` will fail with a `405 Method Not Allowed` response. The tests assert `'PATCH'` which keeps them consistent with the implementation, but they won't catch this kind of server-side rejection. Please confirm the intended HTTP verb against the API spec and align the implementation, tests, and PR description accordingly.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PATCH is the intended verb — the endpoint was switched from POST to PATCH in the companion API PR (workos/workos#64535) since it modifies an already-existing claim attempt. I verified the server accepts PATCH via the API e2e suite (agent-admin.controller.e2e-spec.ts, all cases green). The stale "POST" in the description was the only mismatch — I've updated the PR description to say PATCH. No 405 risk.

@m0tzy
m0tzy merged commit 5e4813f into main Jul 21, 2026
8 checks passed
@m0tzy
m0tzy deleted the devin/1783009238-add-create-claim-attempt branch July 21, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants